//===============================
//  功能 ：备注 
//  作者 ：上中野辅亚瑟王 
//  创建时间 ：2023-05-31  18-29-19 
//  Unity版本  ：2019.4.35f1 
//  变更时间 :  2023-05-31  18-29-19 
//===============================





using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace ZS.U3D.BASE.Runtime.StateMachine
{
    public class StateMachine
    {
        private readonly Dictionary<string, IStateNode> _nodes = new Dictionary<string, IStateNode>();
        private IStateNode _currentNode;
        private IStateNode _previousNode;

        public object Owner { private set; get; }

        public string CurrentNode {
            get 
            {
                if (_currentNode==null)
                {
                    return string.Empty;
                }
                return _currentNode.GetType().FullName;
            }
        }

        public string PreviousNode {
            get {
                if (_previousNode==null)
                {
                    return string.Empty;
                }
                return _previousNode.GetType().FullName;
            }
        }

        public StateMachine(object owner) {
            Owner = owner;
        }

        public void Update() {
            if (_currentNode!=null)
            {
                _currentNode.OnUpdate();
            }
        }


        /// <summary>
		/// 加入一个节点
		/// </summary>
		public void AddNode<TNode>(params object[] ps) where TNode : IStateNode
        {
            var nodeType = typeof(TNode);
            var stateNode = Activator.CreateInstance(nodeType) as IStateNode;
            AddNode(stateNode,ps);
        }

        internal void AddNode(IStateNode stateNode,params object[] ps)
        {
            if (stateNode == null)
            {
                MyDebug.LogWarning($"{nameof(stateNode)} is null !");
                return;
            }

            var nodeType = stateNode.GetType();
            var nodeName = nodeType.FullName;

            if (_nodes.ContainsKey(nodeName) == false)
            {
                stateNode.OnCreate(this,ps);
                _nodes.Add(nodeName, stateNode);
            }
            else
            {
                MyDebug.LogError($"State node already existed : {nodeName}");
            }
        }



        /// <summary>
        /// 启动状态机
        /// </summary>
        public void Run<TNode>() where TNode : IStateNode
        {
            var nodeType = typeof(TNode);
            var nodeName = nodeType.FullName;
            Run(nodeName);
        }

        internal void Run(Type entryNode)
        {
            var nodeName = entryNode.FullName;
            Run(nodeName);
        }

        internal void Run(string entryNode)
        {
            _currentNode = TryGetNode(entryNode);
            _previousNode = _currentNode;

            if (_currentNode == null)
                throw new Exception($"Not found entry node: {entryNode }");

            _currentNode.OnStart();
        }


        /// <summary>
		/// 转换状态节点
		/// </summary>
		public void ChangeState<TNode>() where TNode : IStateNode
        {
            var nodeType = typeof(TNode);
            var nodeName = nodeType.FullName;
            ChangeState(nodeName);
        }
        internal void ChangeState(Type nodeType)
        {
            var nodeName = nodeType.FullName;
            ChangeState(nodeName);
        }

        internal void ChangeState(string nodeName)
        {
            if (string.IsNullOrEmpty(nodeName))
                throw new ArgumentNullException();

            IStateNode node = TryGetNode(nodeName);
            if (node == null)
            {
                MyDebug.LogError($"Can not found state node : {nodeName}");
                return;
            }

            if (node == _currentNode)
            {
                MyDebug.LogError($"Can not change the Same State  {_currentNode.GetType().FullName} --> {node.GetType().FullName}");
                return;
            }

            MyDebug.Log($"{_currentNode.GetType().FullName} --> {node.GetType().FullName}");

            _previousNode = _currentNode;
            _currentNode.OnEnd();
            _currentNode = node;
            _currentNode.OnStart();
        }


        internal IStateNode TryGetNode(string nodeName) {
            _nodes.TryGetValue(nodeName,out IStateNode result);
            return result;
        }

    }
}
